home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / sq.cq / sq.c
Encoding:
C/C++ Source or Header  |  1985-04-12  |  21.1 KB  |  829 lines

  1. static char *sccsid = "@(#)sq.c         1.7u (UCF) 82/12/15";
  2. /*
  3.  *   sq.c - CP/M compatible file squeezer utility
  4.  *
  5.  *   compile as follows:
  6.  *   cc [-DVAX] -O sq.c -o sq
  7.  *       (define VAX only if running on VAX)
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <signal.h>
  12.  
  13. #define TRUE 1
  14. #define FALSE 0
  15. #define ERROR (-1)
  16. #define PATHLEN312/* Number of characters allowed in pathname */
  17. #define ALTNAME "sq.out"
  18.  
  19. /* Definitions and external declarations */
  20.  
  21. #define RECOGNIZE 0xFF76/* unlikely pattern */
  22.  
  23. /* *** Stuff for first translation module *** */
  24.  
  25. #define DLE 0x90
  26.  
  27.  
  28. /* *** Stuff for second translation module *** */
  29.  
  30. #define SPEOF 256/* special endfile token */
  31. #define NUMVALS 257/* 256 data values plus SPEOF*/
  32.  
  33.  
  34. #ifdef VAX   /*  we only want 16 bit integers  */
  35.  
  36. typedef short INT;
  37. typedef unsigned short UNSIGNED;
  38.  
  39. #else   /*  PDP-11 and other 16-bit machines  */
  40.  
  41. typedef int INT;
  42. typedef unsigned UNSIGNED;
  43.  
  44. #endif
  45.  
  46.  
  47. /* Definitions and external declarations */
  48.  
  49. INT Usestd;/* Use stdout for squeezed output */
  50. UNSIGNED crc;/* error check code */
  51.  
  52. /* *** Stuff for first translation module *** */
  53.  
  54. INT likect;/*count of consecutive identical chars */
  55. INT lastchar, newchar;
  56. char state;
  57.  
  58. /* states */
  59.  
  60. #define NOHIST0 /*don't consider previous input*/
  61. #define SENTCHAR 1 /*lastchar set, no lookahead yet */
  62. #define SENDNEWC 2 /*newchar set, previous sequence done */
  63. #define SENDCNT 3 /*newchar set, DLE sent, send count next */
  64.  
  65. /* *** Stuff for second translation module *** */
  66.  
  67. #define NOCHILD -1/* indicates end of path through tree */
  68. #define NUMNODES (NUMVALS + NUMVALS - 1)/* nbr of nodes */
  69.  
  70. #define MAXCOUNT (UNSIGNED) 65535/* biggest UNSIGNED integer */
  71.  
  72. /* The following array of structures are the nodes of the
  73.  * binary trees. The first NUMVALS nodes becomethe leaves of the
  74.  * final tree and represent the values of the data bytes being
  75.  * encoded and the special endfile, SPEOF.
  76.  * The remaining nodes become the internal nodes of the final tree.
  77.  */
  78.  
  79. structnd {
  80. UNSIGNED weight;/* number of appearances */
  81. INT tdepth;/* length on longest path in tre*/
  82. INT lchild, rchild;/* indexes to next level */
  83. } node[NUMNODES];
  84.  
  85. INT dctreehd;/*index to head node of final tree */
  86.  
  87. /* This is the encoding table:
  88.  * The bit strings have first bit in  low bit.
  89.  * Note that counts were scaled so code fits UNSIGNED integer
  90.  */
  91.  
  92. INT codelen[NUMVALS];/* number of bits in code */
  93. UNSIGNED code[NUMVALS];/* code itself, right adjusted */
  94. UNSIGNED tcode;/* temporary code value */
  95.  
  96.  
  97. /* Variables used by encoding process */
  98.  
  99. INT curin;/* Value currently being encoded */
  100. INT cbitsrem;/* Number of code string bits remaining */
  101. UNSIGNED ccode;/* Current code shifted so next code bit is at right */
  102.  
  103. /* This program compresses a file without losing information.
  104.  * The usq.com program is required to unsqueeze the file
  105.  * before it can be used.
  106.  *
  107.  * Typical compression rates are:
  108.  *.COM6%(Don't bother)
  109.  *.ASM33%(using full ASCII set)
  110.  *.DIC46%(using only uppercase and a few others)
  111.  * Squeezing a really big file takes a few minutes.
  112.  *
  113.  * Useage:
  114.  *sq file ...
  115.  *
  116.  *
  117.  * The squeezed file name is formed by changing the second from last
  118.  * letter of the file type to Q. If there is no file type,
  119.  * the squeezed file type is QQQ. If the name exists it is
  120.  * overwritten!
  121.  *
  122.  * The transformations compress strings of identical bytes and
  123.  * then encode each resulting byte value and EOF as bit strings
  124.  * having lengths in inverse proportion to their frequency of
  125.  * occurrence in the intermediate input stream. The latter uses
  126.  * the Huffman algorithm. Decoding information is included in
  127.  * the squeezed file, so squeezing short files or files with
  128.  * uniformly distributed byte values will actually increase size.
  129.  */
  130.  
  131. /* CHANGE HISTORY:
  132.  * 1.5u **nix version - means output to stdout.
  133.  *  (stdin not allowed becuase sq needs to rewind input, which
  134.  *  won't work with pipes.)
  135.  * Filename generation changed to suit **nix and stdio.
  136.  * 1.6u machine independent output for file compatibility with
  137.  *original CP/M version SQ, when running on machine with
  138.  *IBM byte ordering such as Z8000 and 68000.
  139.  * 1.7u machine independence was still lacking for 32-bit machines
  140.  *      like the VAX-11/780, so a typedef was added.  No action
  141.  *      need be taken if running on a 16-bit machine, but if
  142.  *      running on a VAX, define VAX either on the cc line or
  143.  *      in the program preamble.   Ben Goldfarb 12/13/82
  144.  */
  145.  
  146.  
  147. #define VERSION "1.7u   12-13-82"
  148.  
  149. INT inbackground = 0;
  150.  
  151. INT buildenc(), gethuff(), getc_crc();
  152.  
  153. main(argc, argv)
  154. INT argc;
  155. char *argv[];
  156. {
  157. register INT i,c;
  158.  
  159.  
  160. if (signal(SIGINT, SIG_IGN)==SIG_IGN)
  161. inbackground++;
  162. else
  163. signal(SIGINT, SIG_DFL);
  164. signal(SIGHUP, SIG_IGN);
  165.  
  166. /* Process the parameters in order */
  167. for(i = 1; i < argc; ++i) {
  168. if(strcmp(argv[i], "-")==0)
  169. Usestd = TRUE;
  170. }
  171. for(i = 1; i < argc; ++i) {
  172. if(strcmp(argv[i], "-")!=0)
  173. obey(argv[i]);
  174. }
  175.  
  176. if(argc < 2) {
  177. fprintf(stderr,"File squeezer version %s by\n\tRichard Greenlaw\n\t251 Colony Ct.\n\tGahanna, Ohio 43230\n", VERSION);
  178. fprintf(stderr, "Usage: sq [-] pathname ...\n");
  179. fprintf(stderr, "\t- squeezed output to stdout\n");
  180. exit(1);
  181. }
  182. exit(0);
  183. }
  184.  
  185. obey(p)
  186. char *p;
  187. {
  188. char *w,*q;
  189. char outfile[PATHLEN+2];/* output file spec. */
  190.  
  191. /* First build output file name */
  192.  
  193. strcpy(outfile, p);
  194. /* Find and change output file type */
  195. for(w=q = outfile; *q != '\0'; ++q)/* skip leading /'s */
  196. if( *q == '/')
  197. w = q+1;
  198. for(q = w; *q != '\0'; ++q)
  199. if(*q == '.')
  200. if(*(q + 1) == '\0')
  201. *q = '\0';/* kill trailing dot */
  202. else
  203. switch(*(q+2)) {
  204. case 'q':
  205. case 'Q':
  206. fprintf(stderr, "sq: %s ignored ( already squeezed?)", p);
  207. return;
  208. case '\0':
  209. *(q+3) = '\0';
  210. /* fall thru */
  211. default:
  212. *(q + 2) = 'Q';
  213. goto named;
  214. }
  215. /* No file type */
  216. strcat(outfile, ".QQQ");
  217. named:
  218. if(strlen(w)>14)
  219. strcpy(outfile, ALTNAME);/* check for too long name */
  220. squeeze(p, outfile);
  221. }
  222.  
  223. squeeze(infile, outfile)
  224. char *infile, *outfile;
  225. {
  226. register INT i, c;
  227. FILE *inbuff, *outbuff;/* file buffers */
  228.  
  229. if (!inbackground)
  230. fprintf(stderr, "\n%s -> %s: ", infile, outfile);
  231.  
  232. if((inbuff=fopen(infile, "r")) == NULL) {
  233. fprintf(stderr, "sq: can't open %s\n", infile);
  234. return;
  235. }
  236. if(Usestd)
  237. outbuff=stdout;
  238. else if((outbuff=fopen(outfile, "w")) == NULL) {
  239. fprintf(stderr, "sq: can't create %s\n", outfile);
  240. fclose(inbuff);
  241. return;
  242. }
  243.  
  244. /* First pass - get properties of file */
  245. crc = 0;/* initialize checksum */
  246. if (!inbackground)
  247. fprintf(stderr, "analyzing, ");
  248. init_ncr();
  249. init_huff(inbuff);   
  250. rewind(inbuff);
  251.  
  252. /* Write output file header with decoding info */
  253. wrt_head(outbuff, infile);
  254.  
  255. /* Second pass - encode the file */
  256. if (!inbackground)
  257. fprintf(stderr, "squeezing, ");
  258.  
  259. init_ncr();/* For second pass */
  260.  
  261. /* Translate the input file into the output file */
  262. while((c = gethuff(inbuff)) != EOF)
  263. if(putc(c, outbuff) == ERROR && ferror(outbuff)) {
  264. fprintf(stderr, "sq: write error\n");
  265. goto closeall;
  266. }
  267. if (!inbackground)
  268. fprintf(stderr, " done.\n");
  269. closeall:
  270. fclose(inbuff);
  271. closeout:
  272. fflush(outbuff);
  273. fclose(outbuff);
  274. }
  275.  
  276.  
  277. /* First translation - encoding of repeated characters
  278.  * The code is byte for byte pass through except that
  279.  * DLE is encoded as DLE, zero and repeated byte values
  280.  * are encoded as value, DLE, count for count >= 3.
  281.  */
  282.  
  283. init_ncr()/*initialize getcnr() */
  284. {
  285. state = NOHIST;
  286. }
  287.  
  288. INT
  289. getcnr(iob)
  290. FILE *iob;
  291. {
  292. switch(state) {
  293. case NOHIST:
  294. /* No relevant history */
  295. state = SENTCHAR;
  296. return lastchar = getc_crc(iob);   
  297. case SENTCHAR:
  298. /* Lastchar is set, need lookahead */
  299. switch(lastchar) {
  300. case DLE:
  301. state = NOHIST;
  302. return 0;/* indicates DLE was the data */
  303. case EOF:
  304. return EOF;
  305. default:
  306. for(likect = 1; (newchar = getc_crc(iob)) == lastchar && likect < 255; ++likect)
  307. ;
  308. switch(likect) {
  309. case 1:
  310. return lastchar = newchar;
  311. case 2:
  312. /* just pass through */
  313. state = SENDNEWC;
  314. return lastchar;
  315. default:
  316. state = SENDCNT;
  317. return DLE;
  318. }
  319. }
  320. case SENDNEWC:
  321. /* Previous sequence complete, newchar set */
  322. state = SENTCHAR;
  323. return lastchar = newchar;
  324. case SENDCNT:
  325. /* Sent DLE for repeat sequence, send count */
  326. state = SENDNEWC;
  327. return likect;
  328. default:
  329. fprintf(stderr,"sq: Bug - bad state\n");
  330. exit(1);
  331. /* NOTREACHED */
  332. }
  333. }
  334.  
  335.  
  336. /******** Second translation - bytes to variable length bit strings *********/
  337.  
  338.  
  339. /* This translation uses the Huffman algorithm to develop a
  340.  * binary tree representing the decoding information for
  341.  * a variable length bit string code for each input value.
  342.  * Each string's length is in inverse proportion to its
  343.  * frequency of appearance in the incoming data stream.
  344.  * The encoding table is derived from the decoding table.
  345.  *
  346.  * The range of valid values into the Huffman algorithm are
  347.  * the values of a byte stored in an integer plus the special
  348.  * endfile value chosen to be an adjacent value. Overall, 0-SPEOF.
  349.  *
  350.  * The "node" array of structures contains the nodes of the
  351.  * binary tree. The first NUMVALS nodes are the leaves of the
  352.  * tree and represent the values of the data bytes being
  353.  * encoded and the special endfile, SPEOF.
  354.  * The remaining nodes become the internal nodes of the tree.
  355.  *
  356.  * In the original design it was believed that
  357.  * a Huffman code would fit in the same number of
  358.  * bits that will hold the sum of all the counts.
  359.  * That was disproven by a user's file and was a rare but
  360.  * infamous bug. This version attempts to choose among equally
  361.  * weighted subtrees according to their maximum depths to avoid
  362.  * unnecessarily long codes. In case that is not sufficient
  363.  * to guarantee codes <= 16 bits long, we initially scale
  364.  * the counts so the total fits in an unsigned integer, but
  365.  * if codes longer than 16 bits are generated the counts are
  366.  * rescaled to a lower ceiling and code generation is retried.
  367.  */
  368.  
  369. /* Initialize the Huffman translation. This requires reading
  370.  * the input file through any preceding translation functions
  371.  * to get the frequency distribution of the various values.
  372.  */
  373.  
  374. init_huff(ib)          
  375. FILE *ib;
  376. {
  377. register INT c, i;
  378. INT btlist[NUMVALS];/* list of intermediate binary trees */
  379. INT listlen;/* length of btlist */
  380. UNSIGNED *wp;/* simplifies weight counting */
  381. UNSIGNED ceiling;/* limit for scaling */
  382.  
  383. /* Initialize tree nodes to no weight, no children */
  384. init_tree();
  385.  
  386. /* Build frequency info in tree */
  387. do {
  388. c = getcnr(ib);        
  389. if(c == EOF)
  390. c = SPEOF;
  391. if(*(wp = &node[c].weight) !=  MAXCOUNT)
  392. ++(*wp);
  393. while(c != SPEOF);
  394.  
  395. ceiling = MAXCOUNT;
  396.  
  397. do {/* Keep trying to scale and encode */
  398. if(ceiling != MAXCOUNT)
  399. fprintf(stderr, "sq: *** rescaling ***, ");
  400. scale(ceiling);
  401. ceiling /= 2;/* in case we rescale */
  402.  
  403. /* Build list of single node binary trees having
  404.  * leaves for the input values with non-zero counts
  405.  */
  406. for(i = listlen = 0; i < NUMVALS; ++i)
  407. if(node[i].weight != 0) {
  408. node[i].tdepth = 0;
  409. btlist[listlen++] = i;
  410. }
  411.  
  412. /* Arrange list of trees into a heap with the entry
  413.  * indexing the node with the least weight at the top.
  414.  */
  415. heap(btlist, listlen);
  416.  
  417. /* Convert the list of trees to a single decoding tree */
  418. bld_tree(btlist, listlen);
  419.  
  420. /* Initialize the encoding table */
  421. init_enc();
  422.  
  423. /* Try to build encoding table.
  424.  * Fail if any code is > 16 bits long.
  425.  */
  426. while(buildenc(0, dctreehd) == ERROR);
  427.  
  428. /* Initialize encoding variables */
  429. cbitsrem = 0;/*force initial read */
  430. curin = 0;/*anything but endfile*/
  431. }
  432.  
  433. /* The count of number of occurrances of each input value
  434.  * have already been prevented from exceeding MAXCOUNT.
  435.  * Now we must scale them so that their sum doesn't exceed
  436.  * ceiling and yet no non-zero count can become zero.
  437.  * This scaling prevents errors in the weights of the
  438.  * interior nodes of the Huffman tree and also ensures that
  439.  * the codes will fit in an unsigned integer. Rescaling is
  440.  * used if necessary to limit the code length.
  441.  */
  442.  
  443. scale(ceil)
  444. UNSIGNED ceil;/* upper limit on total weight */
  445. {
  446. register INT i,c;
  447. INT ovflw, divisor;
  448. UNSIGNED w, sum;
  449. char increased;/* flag */
  450.  
  451. do {
  452. for(i = sum = ovflw = 0; i < NUMVALS; ++i) {
  453. if(node[i].weight > (ceil - sum))
  454. ++ovflw;
  455. sum += node[i].weight;
  456. }
  457.  
  458. divisor = ovflw + 1;
  459.  
  460. /* Ensure no non-zero values are lost */
  461. increased = FALSE;
  462. for(i = 0; i < NUMVALS; ++i) {
  463. w = node[i].weight;
  464. if (w < divisor && w != 0) {
  465. /* Don't fail to provide a code if it's used at all */
  466. node[i].weight = divisor;
  467. increased = TRUE;
  468. }
  469. }
  470. while(increased);
  471.  
  472. /* Scaling factor choosen, now scale */
  473. if(divisor > 1)
  474. for(i = 0; i < NUMVALS; ++i)
  475. node[i].weight /= divisor;
  476. }
  477.  
  478. /* heap() and adjust() maintain a list of binary trees as a
  479.  * heap with the top indexing the binary tree on the list
  480.  * which has the least weight or, in case of equal weights,
  481.  * least depth in its longest path. The depth part is not
  482.  * strictly necessary, but tends to avoid long codes which
  483.  * might provoke rescaling.
  484.  */
  485.  
  486. heap(list, length)
  487. INT list[], length;
  488. {
  489. register INT i;
  490.  
  491. for(i = (length - 2) / 2; i >= 0; --i)
  492. adjust(list, i, length - 1);
  493. }
  494.  
  495. /* Make a heap from a heap with a new top */
  496.  
  497. adjust(list, top, bottom)
  498. INT list[], top, bottom;
  499. {
  500. register INT k, temp;
  501.  
  502. k = 2 * top + 1;/* left child of top */
  503. temp = list[top];/* remember root node of top tree */
  504. if( k <= bottom) {
  505. if( k < bottom && cmptrees(list[k], list[k + 1]))
  506. ++k;
  507.  
  508. /* k indexes "smaller" child (in heap of trees) of top */
  509. /* now make top index "smaller" of old top and smallest child */
  510. if(cmptrees(temp, list[k])) {
  511. list[top] = list[k];
  512. list[k] = temp;
  513. /* Make the changed list a heap */
  514. adjust(list, k, bottom); /*recursive*/
  515. }
  516. }
  517. }
  518.  
  519. /* Compare two trees, if a > b return true, else return false
  520.  * note comparison rules in previous comments.
  521.  */
  522.  
  523. cmptrees(a, b)
  524. INT a, b;/* root nodes of trees */
  525. {
  526. if(node[a].weight > node[b].weight)
  527. return TRUE;
  528. if(node[a].weight == node[b].weight)
  529. if(node[a].tdepth > node[b].tdepth)
  530. return TRUE;
  531. return FALSE;
  532. }
  533.  
  534. /* HUFFMAN ALGORITHM: develops the single element trees
  535.  * into a single binary tree by forming subtrees rooted in
  536.  * interior nodes having weights equal to the sum of weights of all
  537.  * their descendents and having depth counts indicating the
  538.  * depth of their longest paths.
  539.  *
  540.  * When all trees have been formed into a single tree satisfying
  541.  * the heap property (on weight, with depth as a tie breaker)
  542.  * then the binary code assigned to a leaf (value to be encoded)
  543.  * is then the series of left (0) and right (1)
  544.  * paths leading from the root to the leaf.
  545.  * Note that trees are removed from the heaped list by
  546.  * moving the last element over the top element and
  547.  * reheaping the shorter list.
  548.  */
  549.  
  550. bld_tree(list, len)
  551. INT list[];
  552. INT len;
  553. {
  554. register INT freenode;/* next free node in tree */
  555. register struct nd *frnp;/* free node pointer */
  556. INT lch, rch;/* temporaries for left, right children */
  557. INT i;
  558.  
  559. /* Initialize index to next available (non-leaf) node.
  560.  * Lower numbered nodes correspond to leaves (data values).
  561.  */
  562. freenode = NUMVALS;
  563.  
  564. while(len > 1) {
  565. /* Take from list two btrees with least weight
  566.  * and build an interior node pointing to them.
  567.  * This forms a new tree.
  568.  */
  569. lch = list[0];/* This one will be left child */
  570.  
  571. /* delete top (least) tree from the list of trees */
  572. list[0] = list[--len];
  573. adjust(list, 0, len - 1);
  574.  
  575. /* Take new top (least) tree. Reuse list slot later */
  576. rch = list[0];/* This one will be right child */
  577.  
  578. /* Form new tree from the two least trees using
  579.  * a free node as root. Put the new tree in the list.
  580.  */
  581. frnp = &node[freenode];/* address of next free node */
  582. list[0] = freenode++;/* put at top for now */
  583. frnp->lchild = lch;
  584. frnp->rchild = rch;
  585. frnp->weight = node[lch].weight + node[rch].weight;
  586. frnp->tdepth = 1 + maxchar(node[lch].tdepth, node[rch].tdepth);
  587. /* reheap list  to get least tree at top*/
  588. adjust(list, 0, len - 1);
  589. }
  590. dctreehd = list[0];/*head of final tree */
  591. }
  592.  
  593. /* ???????????? */
  594. maxchar(a, b)
  595. {
  596. return a > b ? a : b;
  597. }
  598. /* Initialize all nodes to single element binary trees
  599.  * with zero weight and depth.
  600.  */
  601.  
  602. init_tree()
  603. {
  604. register INT i;
  605.  
  606. for(i = 0; i < NUMNODES; ++i) {
  607. node[i].weight = 0;
  608. node[i].tdepth = 0;
  609. node[i].lchild = NOCHILD;
  610. node[i].rchild = NOCHILD;
  611. }
  612. }
  613.  
  614. init_enc()
  615. {
  616. register INT i;
  617.  
  618. /* Initialize encoding table */
  619. for(i = 0; i < NUMVALS; ++i) {
  620. codelen[i] = 0;
  621. }
  622. }
  623.  
  624. /* Recursive routine to walk the indicated subtree and level
  625.  * and maintain the current path code in bstree. When a leaf
  626.  * is found the entire code string and length are put into
  627.  * the encoding table entry for the leaf's data value .
  628.  *
  629.  * Returns ERROR if codes are too long.
  630.  */
  631.  
  632. INT/* returns ERROR or NULL */
  633. buildenc(level, root)
  634. INT level;/* level of tree being examined, from zero */
  635. INT root; /* root of subtree is also data value if leaf */
  636. {
  637. register INT l, r;
  638.  
  639. l = node[root].lchild;
  640. r = node[root].rchild;
  641.  
  642. if( l == NOCHILD && r == NOCHILD) {
  643. /* Leaf. Previous path determines bit string
  644.  * code of length level (bits 0 to level - 1).
  645.  * Ensures unused code bits are zero.
  646.  */
  647. codelen[root] = level;
  648. code[root] = tcode & (((UNSIGNED)~0) >> (16 - level));
  649. return (level > 16) ? ERROR : NULL;
  650. else {
  651. if( l != NOCHILD) {
  652. /* Clear path bit and continue deeper */
  653. tcode &= ~(1 << level);
  654. /* NOTE RECURSION */
  655. if(buildenc(level + 1, l) == ERROR)
  656. return ERROR;
  657. }
  658. if(r != NOCHILD) {
  659. /* Set path bit and continue deeper */
  660. tcode |= 1 << level;
  661. /* NOTE RECURSION */
  662. if(buildenc(level + 1, r) == ERROR)
  663. return ERROR;
  664. }
  665. }
  666. return NULL;/* if we got here we're ok so far */
  667. }
  668.  
  669. /* Write out the header of the compressed file */
  670.  
  671. wrt_head(ob, infile)
  672. FILE *ob;
  673. char *infile;/* input file name (w/ or w/o drive) */
  674. {
  675. register INT l,r;
  676. INT i, k;
  677. INT numnodes;/* nbr of nodes in simplified tree */
  678.  
  679. putwe(RECOGNIZE, ob);/* identifies as compressed */
  680. putwe(crc, ob);/* unsigned sum of original data */
  681.  
  682. /* Record the original file name w/o drive */
  683. if(*(infile + 1) == ':')
  684. infile += 2;/* skip drive */
  685.  
  686. do {
  687. putce(*infile, ob);
  688. while(*(infile++) != '\0');
  689.  
  690.  
  691. /* Write out a simplified decoding tree. Only the interior
  692.  * nodes are written. When a child is a leaf index
  693.  * (representing a data value) it is recoded as
  694.  * -(index + 1) to distinguish it from interior indexes
  695.  * which are recoded as positive indexes in the new tree.
  696.  * Note that this tree will be empty for an empty file.
  697.  */
  698.  
  699. numnodes = dctreehd < NUMVALS ? 0 : dctreehd - (NUMVALS -1);
  700. putwe(numnodes, ob);
  701.  
  702. for(k = 0, i = dctreehd; k < numnodes; ++k, --i) {
  703. l = node[i].lchild;
  704. r = node[i].rchild;
  705. l = l < NUMVALS ? -(l + 1) : dctreehd - l;
  706. r = r < NUMVALS ? -(r + 1) : dctreehd - r;
  707. putwe(l, ob);/* left child */
  708. putwe(r, ob);/* right child */
  709. }
  710. }
  711.  
  712. /* Get an encoded byte or EOF. Reads from specified stream AS NEEDED.
  713.  *
  714.  * There are two unsynchronized bit-byte relationships here.
  715.  * The input stream bytes are converted to bit strings of
  716.  * various lengths via the static variables named c...
  717.  * These bit strings are concatenated without padding to
  718.  * become the stream of encoded result bytes, which this
  719.  * function returns one at a time. The EOF (end of file) is
  720.  * converted to SPEOF for convenience and encoded like any
  721.  * other input value. True EOF is returned after that.
  722.  *
  723.  * The original gethuff() called a seperate function,
  724.  * getbit(), but that more readable version was too slow.
  725.  */
  726.  
  727. INT/*  Returns byte values except for EOF */
  728. gethuff(ib)
  729. FILE *ib;
  730. {
  731. INT rbyte;/* Result byte value */
  732. INT need, take;/* numbers of bits */
  733.  
  734. rbyte = 0;
  735. need = 8;/* build one byte per call */
  736.  
  737. /* Loop to build a byte of encoded data
  738.  * Initialization forces read the first time
  739.  */
  740.  
  741. loop:
  742. if(cbitsrem >= need) {
  743. /* Current code fullfills our needs */
  744. if(need == 0)
  745. return rbyte;
  746. /* Take what we need */
  747. rbyte |= ccode << (8 - need);
  748. /* And leave the rest */
  749. ccode >>= need;
  750. cbitsrem -= need;
  751. return rbyte;
  752. }
  753.  
  754. /* We need more than current code */
  755. if(cbitsrem > 0) {
  756. /* Take what there is */
  757. rbyte |= ccode << (8 - need);
  758. need -= cbitsrem;
  759. }
  760. /* No more bits in current code string */
  761. if(curin == SPEOF) {
  762. /* The end of file token has been encoded. If
  763.  * result byte has data return it and do EOF next time
  764.  */
  765. cbitsrem = 0;
  766.  
  767. /*NOTE: +0 is to fight compiler bug? */
  768. return (need == 8) ? EOF : rbyte + 0;
  769. }
  770.  
  771. /* Get an input byte */
  772. if((curin = getcnr(ib)) == EOF)
  773. curin = SPEOF;/* convenient for encoding */
  774.  
  775. /* Get the new byte's code */
  776. ccode = code[curin];
  777. cbitsrem = codelen[curin];
  778.  
  779. goto loop;
  780. }
  781.  
  782.  
  783. /* Get next byte from file and update checksum */
  784.  
  785. INT
  786. getc_crc(ib)
  787. FILE *ib;
  788. {
  789. register INT c;
  790.  
  791. c = getc(ib);
  792. if(c != EOF)
  793. crc += c;/* checksum */
  794. return c;
  795. }
  796.  
  797. /* Output functions with error reporting */
  798.  
  799. putce(c, iob)
  800. INT c;
  801. FILE *iob;
  802. {
  803. if(putc(c, iob) == ERROR && ferror(iob)) {
  804. fprintf(stderr, "sq: write error\n");
  805. exit(1);
  806. }
  807. }
  808.  
  809. /*
  810.  * machine independent put-word that writes low order byte first
  811.  *  (compatible with CP/M original) regardless of host cpu.
  812.  */
  813. putwe(w, iob)
  814. INT w;
  815. FILE *iob;
  816. {
  817. putc(w, iob);
  818. putc(w>>8, iob);
  819. if (ferror(iob)) {
  820. fprintf(stderr, "sq: write error\n");
  821. exit(1);
  822. }
  823. }
  824.